home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / bind-contrib.tar.gz / bind-contrib.tar / contrib / host / send.c < prev    next >
C/C++ Source or Header  |  1996-11-10  |  21KB  |  840 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char Version[] = "@(#)send.c    e07@nikhef.nl (Eric Wassenaar) 961013";
  22. #endif
  23.  
  24. #if defined(apollo) && defined(lint)
  25. #define __attribute(x)
  26. #endif
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <setjmp.h>
  31. #include <signal.h>
  32. #include <sys/time.h>
  33.  
  34. #include <sys/types.h>        /* not always automatically included */
  35. #include <sys/param.h>
  36. #include <sys/socket.h>
  37. #include <netinet/in.h>
  38.  
  39. #undef NOERROR            /* in <sys/streams.h> on solaris 2.x */
  40. #include <arpa/nameser.h>
  41. #include <resolv.h>
  42.  
  43. #include "port.h"        /* various portability definitions */
  44. #include "conf.h"        /* various configuration definitions */
  45.  
  46. #define input            /* read-only input parameter */
  47. #define output            /* modified output parameter */
  48.  
  49. #define bitset(a,b)    (((a) & (b)) != 0)
  50. #define setalarm(n)    (void) alarm((unsigned int)(n))
  51.  
  52. extern int errno;
  53. extern res_state_t _res;    /* defined in res_init.c */
  54.  
  55. char *dbprefix = DBPREFIX;    /* prefix for debug messages to stdout */
  56.  
  57. static int timeout;        /* connection read timeout */
  58. static struct sockaddr_in from;    /* address of inbound packet */
  59. static struct sockaddr *from_sa = (struct sockaddr *)&from;
  60.  
  61. char *inet_ntoa        PROTO((struct in_addr));
  62. unsigned int alarm    PROTO((unsigned int));
  63.  
  64. #ifdef HOST_RES_SEND
  65. int res_send        PROTO((CONST qbuf_t *, int, qbuf_t *, int));
  66. void _res_close        PROTO((void));
  67. static int check_from    PROTO((void));
  68. static int send_stream    PROTO((struct sockaddr_in *, qbuf_t *, int, qbuf_t *, int));
  69. static int send_dgram    PROTO((struct sockaddr_in *, qbuf_t *, int, qbuf_t *, int));
  70. #endif /*HOST_RES_SEND*/
  71. static sigtype_t timer    PROTO((int));
  72. int _res_connect    PROTO((int, struct sockaddr_in *, int));
  73. int _res_write        PROTO((int, struct sockaddr_in *, char *, char *, int));
  74. int _res_read        PROTO((int, struct sockaddr_in *, char *, char *, int));
  75. static int recv_sock    PROTO((int, char *, int));
  76. void _res_perror    PROTO((struct sockaddr_in *, char *, char *));
  77.  
  78. #ifdef HOST_RES_SEND
  79.  
  80. /*
  81. ** RES_SEND -- Send nameserver query and retrieve answer
  82. ** -----------------------------------------------------
  83. **
  84. **    Returns:
  85. **        Length of (untruncated) nameserver answer, if obtained.
  86. **        -1 if an error occurred (errno set appropriately).
  87. **
  88. **    This is a simplified version of the BIND 4.8.3 res_send().
  89. **    - Always use connected datagrams to get proper error messages.
  90. **    - Do not only return ETIMEDOUT or ECONNREFUSED in datagram mode,
  91. **      but also host or network unreachable status if appropriate.
  92. **    - Never leave a connection open after we got an answer.
  93. **    - No special ECONNRESET handling when using virtual circuits.
  94. **
  95. **    Note that this private version of res_send() is not only called
  96. **    directly by 'host' but also indirectly by gethostbyname() or by
  97. **    gethostbyaddr() via their resolver interface routines.
  98. */
  99.  
  100. int
  101. res_send(query, querylen, answer, anslen)
  102. input CONST qbuf_t *query;        /* location of formatted query buffer */
  103. input int querylen;            /* length of query buffer */
  104. output qbuf_t *answer;            /* location of buffer to store answer */
  105. input int anslen;            /* maximum size of answer buffer */
  106. {
  107.     HEADER *bp = (HEADER *)answer;
  108.     struct sockaddr_in *addr;    /* the server address to connect to */
  109.     int v_circuit;            /* virtual circuit or datagram switch */
  110.     int servfail[MAXNS];        /* saved failure codes per nameserver */
  111.     register int try, ns;
  112.     register int n;
  113.  
  114.     /* make sure resolver has been initialized */
  115.     if (!bitset(RES_INIT, _res.options) && res_init() == -1)
  116.         return(-1);
  117.  
  118.     if (bitset(RES_DEBUG, _res.options))
  119.     {
  120.         printf("%sres_send()\n", dbprefix);
  121.         pr_query(query, querylen, stdout);
  122.     }
  123.  
  124.     /* use virtual circuit if requested or if necessary */
  125.     v_circuit = bitset(RES_USEVC, _res.options) || (querylen > PACKETSZ);
  126.  
  127.     /* reset server failure codes */
  128.     for (ns = 0; ns < MAXNS; ns++)
  129.         servfail[ns] = 0;
  130.  
  131. /*
  132.  * Do _res.retry attempts for each of the _res.nscount addresses.
  133.  * Upon failure, the current server will be marked bad if we got
  134.  * an error condition which makes it unlikely that we will succeed
  135.  * the next time we try this server.
  136.  * Internal operating system failures, such as temporary lack of
  137.  * resources, do not fall in that category.
  138.  */
  139.     for (try = 0; try < _res.retry; try++)
  140.     {
  141.         for (ns = 0; ns < _res.nscount; ns++)
  142.         {
  143.         /* skip retry if server failed permanently */
  144.         if (servfail[ns])
  145.             continue;
  146.  
  147.         /* fetch server address */
  148.         addr = &nslist(ns);
  149. retry:
  150.         if (bitset(RES_DEBUG, _res.options))
  151.             printf("%sQuerying server (# %d) %s address = %s\n", dbprefix,
  152.                 ns+1, v_circuit ? "tcp" : "udp", inet_ntoa(addr->sin_addr));
  153.  
  154.         if (v_circuit)
  155.         {
  156.             /* at most one attempt per server */
  157.             try = _res.retry;
  158.  
  159.             /* connect via virtual circuit */
  160.             n = send_stream(addr, query, querylen, answer, anslen);
  161.         }
  162.         else
  163.         {
  164.             /* set datagram read timeout for recv_sock() */
  165.             timeout = (_res.retrans << try);
  166.             if (try > 0)
  167.                 timeout /= _res.nscount;
  168.             if (timeout <= 0)
  169.                 timeout = 1;
  170.  
  171.             /* connect via datagram */
  172.             n = send_dgram(addr, query, querylen, answer, anslen);
  173.  
  174.             /* check truncation; use v_circuit with same server */
  175.             if ((n > 0) && bp->tc)
  176.             {
  177.                 if (bitset(RES_DEBUG, _res.options))
  178.                     printf("%struncated answer, %d bytes\n", dbprefix, n);
  179.  
  180.                 if (!bitset(RES_IGNTC, _res.options))
  181.                 {
  182.                     v_circuit = 1;
  183.                     goto retry;
  184.                 }
  185.             }
  186.         }
  187.  
  188.         if (n <= 0)
  189.         {
  190.             switch (errno)
  191.             {
  192.                 case ECONNREFUSED:
  193.                 case ENETDOWN:
  194.                 case ENETUNREACH:
  195.                 case EHOSTDOWN:
  196.                 case EHOSTUNREACH:
  197.                 servfail[ns] = errno;
  198.                 break;
  199.             }
  200.  
  201.             /* try next server */
  202.             continue;
  203.         }
  204.  
  205.         if (bitset(RES_DEBUG, _res.options))
  206.         {
  207.             printf("%sgot answer, %d bytes:\n", dbprefix, n);
  208.             pr_query(answer, (n > anslen) ? anslen : n, stdout);
  209.         }
  210.  
  211.         /* we have an answer; clear possible error condition */
  212.         errno = 0;
  213.         return(n);
  214.         }
  215.     }
  216.  
  217.     /* no answer obtained; return error condition */
  218.     return(-1);
  219. }
  220.  
  221. /*
  222. ** _RES_CLOSE -- Close an open stream or dgram connection
  223. ** ------------------------------------------------------
  224. **
  225. **    Returns:
  226. **        None.
  227. */
  228.  
  229. static int srvsock = -1;    /* socket descriptor */
  230.  
  231. void
  232. _res_close()
  233. {
  234.     int save_errno = errno;        /* preserve state */
  235.  
  236.     /* close the connection if open */
  237.     if (srvsock >= 0)
  238.     {
  239.         (void) close(srvsock);
  240.         srvsock = -1;
  241.     }
  242.  
  243.     /* restore state */
  244.     errno = save_errno;
  245. }
  246.  
  247. /*
  248. ** CHECK_FROM -- Make sure the response comes from a known server
  249. ** --------------------------------------------------------------
  250. **
  251. **    Returns:
  252. **        Nonzero if the source address is known.
  253. **        Zero otherwise.
  254. */
  255.  
  256. static int
  257. check_from()
  258. {
  259.     struct sockaddr_in *addr;
  260.     register int ns;
  261.  
  262.     for (ns = 0; ns < _res.nscount; ns++)
  263.     {
  264.         /* fetch server address */
  265.         addr = &nslist(ns);
  266.  
  267.         if (from.sin_family != addr->sin_family)
  268.             continue;
  269.  
  270.         if (from.sin_port != addr->sin_port)
  271.             continue;
  272.  
  273.         /* this allows a reply from any responding server */
  274.         if (addr->sin_addr.s_addr == INADDR_ANY)
  275.             return(1);
  276.  
  277.         if (from.sin_addr.s_addr == addr->sin_addr.s_addr)
  278.             return(1);
  279.     }
  280.  
  281.     /* matches none of the known addresses */
  282.     return(0);
  283. }
  284.  
  285. /*
  286. ** SEND_STREAM -- Query nameserver via virtual circuit
  287. ** ---------------------------------------------------
  288. **
  289. **    Returns:
  290. **        Length of (untruncated) nameserver answer, if obtained.
  291. **        -1 if an error occurred.
  292. **
  293. **    A new socket is allocated for each call, and it is never
  294. **    left open. Checking the packet id is rather redundant.
  295. **
  296. **    Note that connect() is the call that is allowed to fail
  297. **    under normal circumstances. All other failures generate
  298. **    an unconditional error message.
  299. **    Note that truncation is handled within _res_read().
  300. */
  301.  
  302. static int
  303. send_stream(addr, query, querylen, answer, anslen)
  304. input struct sockaddr_in *addr;        /* the server address to connect to */
  305. input qbuf_t *query;            /* location of formatted query buffer */
  306. input int querylen;            /* length of query buffer */
  307. output qbuf_t *answer;            /* location of buffer to store answer */
  308. input int anslen;            /* maximum size of answer buffer */
  309. {
  310.     char *host = NULL;        /* name of server is unknown */
  311.     HEADER *qp = (HEADER *)query;
  312.     HEADER *bp = (HEADER *)answer;
  313.     register int n;
  314.  
  315. /*
  316.  * Setup a virtual circuit connection.
  317.  */
  318.     srvsock = socket(AF_INET, SOCK_STREAM, 0);
  319.     if (srvsock < 0)
  320.     {
  321.         _res_perror(addr, host, "socket");
  322.         return(-1);
  323.     }
  324.  
  325.     if (_res_connect(srvsock, addr, sizeof(*addr)) < 0)
  326.     {
  327.         if (bitset(RES_DEBUG, _res.options))
  328.             _res_perror(addr, host, "connect");
  329.         _res_close();
  330.         return(-1);
  331.     }
  332.  
  333.     if (bitset(RES_DEBUG, _res.options))
  334.         printf("%sconnected to %s\n", dbprefix, inet_ntoa(addr->sin_addr));
  335.  
  336. /*
  337.  * Send the query buffer.
  338.  */
  339.     if (_res_write(srvsock, addr, host, (char *)query, querylen) < 0)
  340.     {
  341.         _res_close();
  342.         return(-1);
  343.     }
  344.  
  345. /*
  346.  * Read the answer buffer.
  347.  */
  348. wait:
  349.     n = _res_read(srvsock, addr, host, (char *)answer, anslen);
  350.     if (n <= 0)
  351.     {
  352.         _res_close();
  353.         return(-1);
  354.     }
  355.  
  356. /*
  357.  * Make sure it is the proper response by checking the packet id.
  358.  */
  359.     if (qp->id != bp->id)
  360.     {
  361.         if (bitset(RES_DEBUG, _res.options))
  362.         {
  363.             printf("%sunexpected answer:\n", dbprefix);
  364.             pr_query(answer, (n > anslen) ? anslen : n, stdout);
  365.         }
  366.         goto wait;
  367.     }
  368.  
  369. /*
  370.  * Never leave the socket open.
  371.  */
  372.     _res_close();
  373.     return(n);
  374. }
  375.  
  376. /*
  377. ** SEND_DGRAM -- Query nameserver via datagram
  378. ** -------------------------------------------
  379. **
  380. **    Returns:
  381. **        Length of nameserver answer, if obtained.
  382. **        -1 if an error occurred.
  383. **
  384. **    Inputs:
  385. **        The global variable ``timeout'' should have been
  386. **        set with the desired timeout value in seconds.
  387. **
  388. **    Sending to a nameserver datagram port with no nameserver running
  389. **    will cause an ICMP port unreachable message to be returned. If the
  390. **    socket is connected, we get an ECONNREFUSED error on the next socket
  391. **    operation, and select returns if the error message is received.
  392. **    Also, we get ENETUNREACH or EHOSTUNREACH errors if appropriate.
  393. **    We thus get a proper error status before timing out.
  394. **    This method usually works only if BSD >= 43.
  395. **
  396. **    Note that send() and recvfrom() are now the calls that are allowed
  397. **    to fail under normal circumstances. All other failures generate
  398. **    an unconditional error message.
  399. */
  400.  
  401. static int
  402. send_dgram(addr, query, querylen, answer, anslen)
  403. input struct sockaddr_in *addr;        /* the server address to connect to */
  404. input qbuf_t *query;            /* location of formatted query buffer */
  405. input int querylen;            /* length of query buffer */
  406. output qbuf_t *answer;            /* location of buffer to store answer */
  407. input int anslen;            /* maximum size of answer buffer */
  408. {
  409.     char *host = NULL;        /* name of server is unknown */
  410.     HEADER *qp = (HEADER *)query;
  411.     HEADER *bp = (HEADER *)answer;
  412.     register int n;
  413.  
  414. /*
  415.  * Setup a connected datagram socket.
  416.  */
  417.     srvsock = socket(AF_INET, SOCK_DGRAM, 0);
  418.     if (srvsock < 0)
  419.     {
  420.         _res_perror(addr, host, "socket");
  421.         return(-1);
  422.     }
  423.  
  424.     if (connect(srvsock, (struct sockaddr *)addr, sizeof(*addr)) < 0)
  425.     {
  426.         _res_perror(addr, host, "connect");
  427.         _res_close();
  428.         return(-1);
  429.     }
  430.  
  431. /*
  432.  * Send the query buffer.
  433.  */
  434.     if (send(srvsock, (char *)query, querylen, 0) != querylen)
  435.     {
  436.         if (bitset(RES_DEBUG, _res.options))
  437.             _res_perror(addr, host, "send");
  438.         _res_close();
  439.         return(-1);
  440.     }
  441.  
  442. /*
  443.  * Wait for the arrival of a reply, timeout, or error message.
  444.  */
  445. wait:
  446.     n = recv_sock(srvsock, (char *)answer, anslen);
  447.     if (n <= 0)
  448.     {
  449.         if (bitset(RES_DEBUG, _res.options))
  450.             _res_perror(addr, host, "recvfrom");
  451.         _res_close();
  452.         return(-1);
  453.     }
  454.  
  455. /*
  456.  * Make sure it is the proper response by checking the packet id.
  457.  */
  458.     if (qp->id != bp->id)
  459.     {
  460.         if (bitset(RES_DEBUG, _res.options))
  461.         {
  462.             printf("%sold answer:\n", dbprefix);
  463.             pr_query(answer, (n > anslen) ? anslen : n, stdout);
  464.         }
  465.         goto wait;
  466.     }
  467.  
  468. /*
  469.  * Make sure it comes from a known server.
  470.  */
  471.     if (!check_from())
  472.     {
  473.         if (bitset(RES_DEBUG, _res.options))
  474.         {
  475.             printf("%sunknown server %s:\n", dbprefix, inet_ntoa(from.sin_addr));
  476.             pr_query(answer, (n > anslen) ? anslen : n, stdout);
  477.         }
  478.         goto wait;
  479.     }
  480.  
  481. /*
  482.  * Never leave the socket open.
  483.  */
  484.     _res_close();
  485.     return(n);
  486. }
  487.  
  488. #endif /*HOST_RES_SEND*/
  489.  
  490. /*
  491. ** _RES_CONNECT -- Connect to a stream (virtual circuit) socket
  492. ** ------------------------------------------------------------
  493. **
  494. **    Returns:
  495. **        0 if successfully connected.
  496. **        -1 in case of failure or timeout.
  497. **
  498. **    Note that we use _res.retrans to override the default
  499. **    connect timeout value.
  500. */
  501.  
  502. static jmp_buf timer_buf;
  503.  
  504. static sigtype_t
  505. /*ARGSUSED*/
  506. timer(sig)
  507. int sig;
  508. {
  509.     longjmp(timer_buf, 1);
  510.     /*NOTREACHED*/
  511. }
  512.  
  513.  
  514. int
  515. _res_connect(sock, addr, addrlen)
  516. input int sock;
  517. input struct sockaddr_in *addr;        /* the server address to connect to */
  518. input int addrlen;
  519. {
  520.     if (setjmp(timer_buf) != 0)
  521.     {
  522.         errno = ETIMEDOUT;
  523.         setalarm(0);
  524.         return(-1);
  525.     }
  526.  
  527.     (void) signal(SIGALRM, timer);
  528.     setalarm(_res.retrans);
  529.  
  530.     if (connect(sock, (struct sockaddr *)addr, addrlen) < 0)
  531.     {
  532.         if (errno == EINTR)
  533.             errno = ETIMEDOUT;
  534.         setalarm(0);
  535.         return(-1);
  536.     }
  537.  
  538.     setalarm(0);
  539.     return(0);
  540. }
  541.  
  542. /*
  543. ** _RES_WRITE -- Write the query buffer via a stream socket
  544. ** --------------------------------------------------------
  545. **
  546. **    Returns:
  547. **        Length of buffer if successfully transmitted.
  548. **        -1 in case of failure (error message is issued).
  549. **
  550. **    The query is sent in two steps: first a single word with
  551. **    the length of the buffer, followed by the buffer itself.
  552. */
  553.  
  554. int
  555. _res_write(sock, addr, host, buf, bufsize)
  556. input int sock;
  557. input struct sockaddr_in *addr;        /* the server address to connect to */
  558. input char *host;            /* name of server to connect to */
  559. input char *buf;            /* location of formatted query buffer */
  560. input int bufsize;            /* length of query buffer */
  561. {
  562.     u_short len;
  563.  
  564. /*
  565.  * Write the length of the query buffer.
  566.  */
  567.     /* len = htons(bufsize); */
  568.     putshort((u_short)bufsize, (u_char *)&len);
  569.  
  570.     if (write(sock, (char *)&len, INT16SZ) != INT16SZ)
  571.     {
  572.         _res_perror(addr, host, "write query length");
  573.         return(-1);
  574.     }
  575.  
  576. /*
  577.  * Write the query buffer itself.
  578.  */
  579.     if (write(sock, buf, bufsize) != bufsize)
  580.     {
  581.         _res_perror(addr, host, "write query");
  582.         return(-1);
  583.     }
  584.  
  585.     return(bufsize);
  586. }
  587.  
  588. /*
  589. ** _RES_READ -- Read the answer buffer via a stream socket
  590. ** -------------------------------------------------------
  591. **
  592. **    Returns:
  593. **        Length of (untruncated) answer if successfully received.
  594. **        -1 in case of failure (error message is issued).
  595. **
  596. **    The answer is read in two steps: first a single word which
  597. **    gives the length of the buffer, followed by the buffer itself.
  598. **    If the answer is too long to fit into the supplied buffer,
  599. **    only the portion that fits will be stored, the residu will be
  600. **    flushed, and the truncation flag will be set.
  601. **
  602. **    Note. The returned length is that of the *un*truncated answer,
  603. **    however, and not the amount of data that is actually available.
  604. **    This may give the caller a hint about new buffer reallocation.
  605. */
  606.  
  607. int
  608. _res_read(sock, addr, host, buf, bufsize)
  609. input int sock;
  610. input struct sockaddr_in *addr;        /* the server address to connect to */
  611. input char *host;            /* name of server to connect to */
  612. output char *buf;            /* location of buffer to store answer */
  613. input int bufsize;            /* maximum size of answer buffer */
  614. {
  615.     u_short len;
  616.     char *buffer;
  617.     int buflen;
  618.     int reslen;
  619.     register int n;
  620.  
  621.     /* set stream timeout for recv_sock() */
  622.     timeout = READTIMEOUT;
  623.  
  624. /*
  625.  * Read the length of answer buffer.
  626.  */
  627.     buffer = (char *)&len;
  628.     buflen = INT16SZ;
  629.  
  630.     while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
  631.     {
  632.         buffer += n;
  633.         buflen -= n;
  634.     }
  635.  
  636.     if (buflen != 0)
  637.     {
  638.         _res_perror(addr, host, "read answer length");
  639.         return(-1);
  640.     }
  641.  
  642. /*
  643.  * Terminate if length is zero.
  644.  */
  645.     /* len = ntohs(len); */
  646.     len = _getshort((u_char *)&len);
  647.     if (len == 0)
  648.         return(0);
  649.  
  650. /*
  651.  * Check for truncation.
  652.  * Do not chop the returned length in case of buffer overflow.
  653.  */
  654.     reslen = 0;
  655.     if ((int)len > bufsize)
  656.     {
  657.         reslen = len - bufsize;
  658.         /* len = bufsize; */
  659.     }
  660.  
  661. /*
  662.  * Read the answer buffer itself.
  663.  * Truncate the answer is the supplied buffer is not big enough.
  664.  */
  665.     buffer = buf;
  666.     buflen = (reslen > 0) ? bufsize : len;
  667.  
  668.     while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
  669.     {
  670.         buffer += n;
  671.         buflen -= n;
  672.     }
  673.  
  674.     if (buflen != 0)
  675.     {
  676.         _res_perror(addr, host, "read answer");
  677.         return(-1);
  678.     }
  679.  
  680. /*
  681.  * Discard the residu to keep connection in sync.
  682.  */
  683.     if (reslen > 0)
  684.     {
  685.         HEADER *bp = (HEADER *)buf;
  686.         char resbuf[PACKETSZ];
  687.  
  688.         buffer = resbuf;
  689.         buflen = (reslen < sizeof(resbuf)) ? reslen : sizeof(resbuf);
  690.  
  691.         while (reslen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
  692.         {
  693.             reslen -= n;
  694.             buflen = (reslen < sizeof(resbuf)) ? reslen : sizeof(resbuf);
  695.         }
  696.  
  697.         if (reslen != 0)
  698.         {
  699.             _res_perror(addr, host, "read residu");
  700.             return(-1);
  701.         }
  702.  
  703.         if (bitset(RES_DEBUG, _res.options))
  704.             printf("%sresponse truncated to %d bytes\n", dbprefix, bufsize);
  705.  
  706.         /* set truncation flag */
  707.         bp->tc = 1;
  708.     }
  709.  
  710.     return(len);
  711. }
  712.  
  713. /*
  714. ** RECV_SOCK -- Read from stream or datagram socket with timeout
  715. ** -------------------------------------------------------------
  716. **
  717. **    Returns:
  718. **        Length of buffer if successfully received.
  719. **        -1 in case of failure or timeout.
  720. **    Inputs:
  721. **        The global variable ``timeout'' should have been
  722. **        set with the desired timeout value in seconds.
  723. **    Outputs:
  724. **        Sets ``from'' to the address of the packet sender.
  725. */
  726.  
  727. static int
  728. recv_sock(sock, buffer, buflen)
  729. input int sock;
  730. output char *buffer;            /* current buffer address */
  731. input int buflen;            /* remaining buffer size */
  732. {
  733.     fd_set fds;
  734.     struct timeval wait;
  735.     int fromlen;
  736.     register int n;
  737.  
  738.     wait.tv_sec = timeout;
  739.     wait.tv_usec = 0;
  740. rewait:
  741.     /* FD_ZERO(&fds); */
  742.     bzero((char *)&fds, sizeof(fds));
  743.     FD_SET(sock, &fds);
  744.  
  745.     /* wait for the arrival of data, or timeout */
  746.     n = select(FD_SETSIZE, &fds, (fd_set *)NULL, (fd_set *)NULL, &wait);
  747.     if (n <= 0)
  748.     {
  749.         if (n < 0 && errno == EINTR)
  750.             goto rewait;
  751.         if (n == 0)
  752.             errno = ETIMEDOUT;
  753.         return(-1);
  754.     }
  755. reread:
  756.     /* fake an error if nothing was actually read */
  757.     fromlen = sizeof(from);
  758.     n = recvfrom(sock, buffer, buflen, 0, from_sa, &fromlen);
  759.     if (n < 0 && errno == EINTR)
  760.         goto reread;
  761.     if (n == 0)
  762.         errno = ECONNRESET;
  763.     return(n);
  764. }
  765.  
  766. /*
  767.  * Alternative version for systems with broken networking code.
  768.  *
  769.  * The select() system call may fail on the solaris 2.4 platform
  770.  * without appropriate patches. However, these patches are reported
  771.  * to break client NFS.
  772.  *
  773.  * This version uses an alarm() instead of select(). This introduces
  774.  * additional system call overhead.
  775.  */
  776.  
  777. #ifdef BROKEN_SELECT
  778.  
  779. static int
  780. recv_sock(sock, buffer, buflen)
  781. input int sock;
  782. output char *buffer;            /* current buffer address */
  783. input int buflen;            /* remaining buffer size */
  784. {
  785.     int fromlen;
  786.     register int n;
  787.  
  788.     if (setjmp(timer_buf) != 0)
  789.     {
  790.         errno = ETIMEDOUT;
  791.         setalarm(0);
  792.         return(-1);
  793.     }
  794.  
  795.     (void) signal(SIGALRM, timer);
  796.     setalarm(timeout);
  797. reread:
  798.     /* fake an error if nothing was actually read */
  799.     fromlen = sizeof(from);
  800.     n = recvfrom(sock, buffer, buflen, 0, from_sa, &fromlen);
  801.     if (n < 0 && errno == EINTR)
  802.         goto reread;
  803.     if (n == 0)
  804.         errno = ECONNRESET;
  805.     setalarm(0);
  806.     return(n);
  807. }
  808.  
  809. #endif /*BROKEN_SELECT*/
  810.  
  811. /*
  812. ** _RES_PERROR -- Issue perror message including host info
  813. ** -------------------------------------------------------
  814. **
  815. **    Returns:
  816. **        None.
  817. */
  818.  
  819. void
  820. _res_perror(addr, host, message)
  821. input struct sockaddr_in *addr;        /* the server address to connect to */
  822. input char *host;            /* name of server to connect to */
  823. input char *message;            /* perror message string */
  824. {
  825.     int save_errno = errno;        /* preserve state */
  826.  
  827.     /* prepend server address and name */
  828.     if (addr != NULL)
  829.         (void) fprintf(stderr, "%s ", inet_ntoa(addr->sin_addr));
  830.     if (host != NULL)
  831.         (void) fprintf(stderr, "(%s) ", host);
  832.  
  833.     /* issue actual message */
  834.     errno = save_errno;
  835.     perror(message);
  836.  
  837.     /* restore state */
  838.     errno = save_errno;
  839. }
  840.